package com.wteam.dragon.model.service.impl;

import cn.hutool.core.lang.Dict;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wteam.dragon.model.mapper.*;
import com.wteam.dragon.model.pojo.bean.User;
import com.wteam.dragon.model.pojo.bean.UsersJobs;
import com.wteam.dragon.model.pojo.bean.UsersRoles;
import com.wteam.dragon.model.pojo.dto.JobSmallDto;
import com.wteam.dragon.model.pojo.dto.RoleSmallDto;
import com.wteam.dragon.model.pojo.dto.UserDto;
import com.wteam.dragon.model.pojo.vo.QueryUserVo;
import com.wteam.dragon.model.service.UserService;
import com.wteam.dragon.system.basebean.bean.ResultMessage;
import com.wteam.dragon.system.exception.BadRequestException;
import com.wteam.dragon.system.exception.EntityNotFoundException;
import com.wteam.dragon.system.util.*;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author 陈晓辉
 * @date 2020-03-15
 */
@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = "user")
public class UserServiceImpl implements UserService {
    private final UserMapper userMapper;
    private final UserDtoMapper userDtoMapper;
    private final UsersRolesMapper usersRolesMapper;
    private final RoleSmallDtoMapper roleSmallDtoMapper;
    private final DeptSmallDtoMapper deptSmallDtoMapper;
    private final JobSmallDtoMapper jobSmallDtoMapper;
    private final UserJobsMapper userJobsMapper;

    @Override
    public ResultMessage pageUser(Page<UserDto> page, QueryUserVo queryUserVo) {
        UserDto like = new UserDto();
        UserDto eq = new UserDto();
        QueryWrapper<UserDto> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().orderByDesc(UserDto::getCreateTime);
        eq.setId(queryUserVo.getId());
        eq.setEnabled(queryUserVo.getEnabled());
        eq.setDeptId(queryUserVo.getDeptId());
        like.setEmail(queryUserVo.getEmail());
        like.setUsername(queryUserVo.getUsername());
        if(queryUserVo.getRoleId() != null){
            like.setRoleIdStr("," + queryUserVo.getRoleId() + ",");
        }
        if (queryUserVo.getStartTime() != null && queryUserVo.getEndTime() != null) {
            queryWrapper.lambda().between(UserDto::getCreateTime, queryUserVo.getStartTime(), queryUserVo.getEndTime());
        }
        WrapperUtil.eq(queryWrapper, eq);
        WrapperUtil.like(queryWrapper, like);
        Page<UserDto> userDtoPage = userDtoMapper.selectPage(page, queryWrapper);
        for (UserDto userDto : userDtoPage.getRecords()) {
            userDto.setDept(deptSmallDtoMapper.selectById(userDto.getDeptId()));
            QueryWrapper<UsersJobs> userJobsQueryWrapper = new QueryWrapper<>();
            userJobsQueryWrapper.lambda().eq(UsersJobs::getUserId, userDto.getId());
            List<UsersJobs> userJobsList = userJobsMapper.selectList(userJobsQueryWrapper);
            Set<JobSmallDto> jobSmallDtoSet = new HashSet<>();
            userJobsList.forEach(usersJobs -> {
                jobSmallDtoSet.add(jobSmallDtoMapper.selectById(usersJobs.getJobId()));
            });
            userDto.setJobs(jobSmallDtoSet);

            QueryWrapper<UsersRoles> usersRolesQueryWrapper = new QueryWrapper<>();
            usersRolesQueryWrapper.lambda().eq(UsersRoles::getUserId, userDto.getId());
            Set<RoleSmallDto> roleSmallDtoSet = new HashSet<>();
            List<UsersRoles> usersRolesList = usersRolesMapper.selectList(usersRolesQueryWrapper);
            usersRolesList.forEach(usersRoles -> {
                roleSmallDtoSet.add(roleSmallDtoMapper.selectById(usersRoles.getRoleId()));
            });
            userDto.setRoles(roleSmallDtoSet);
        }
        Dict dict = Dict.create().set("message", "请求成功")
                .set("userList", userDtoPage);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setResultParam(dict);
        return resultMessage;
    }

    @Override
    @CacheEvict(allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    public ResultMessage addUser(User user, Set<Long> rolesId, Set<Long> jobsId) {
        if (rolesId == null || rolesId.size() == 0) {
            throw new BadRequestException("roleId不能为空");
        }
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.lambda().eq(User::getUsername, user.getUsername());
        User oneUser = userMapper.selectOne(userQueryWrapper);
        if (oneUser != null) {
            throw new BadRequestException("用户名已经存在，请更换用户名");
        }
        if (!StringUtils.isBlank(user.getEmail())) {
            if (!ValidationUtil.isEmail(user.getEmail())) {
                throw new BadRequestException("邮箱格式错误");
            }
        }
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        user.setPassword(encoder.encode(user.getUsername()));
        user.setLastPasswordResetTime(new Timestamp(System.currentTimeMillis()));
        // 添加用户角色搜索
        StringBuilder roleIdStr = new StringBuilder(",");
        rolesId.forEach(roleId -> {
            roleIdStr.append(roleId).append(",");
        });
        user.setRoleIdStr(roleIdStr.toString());
        userMapper.insert(user);
        //添加角色
        for (Long roleId : rolesId) {
            UsersRoles usersRoles = new UsersRoles();
            usersRoles.setRoleId(roleId);
            usersRoles.setUserId(user.getId());
            usersRolesMapper.insert(usersRoles);
        }
        checkLevel(user);
        if (jobsId != null) {
            for (Long jobId : jobsId) {
                UsersJobs usersJobs = new UsersJobs();
                usersJobs.setUserId(user.getId());
                usersJobs.setJobId(jobId);
                userJobsMapper.insert(usersJobs);
            }
        }
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("添加用户成功");
        return resultMessage;
    }

    @Override
    @Caching(evict = {@CacheEvict(value = "menusTree", allEntries = true),
            @CacheEvict(value = "Authorities", allEntries = true),
            @CacheEvict(allEntries = true)})
    @Transactional(rollbackFor = Exception.class)
    public ResultMessage editUser(User user, Set<Long> rolesId, Set<Long> jobsId) {
        checkLevel(user);
        if (user.getUsername() != null || user.getPassword() != null) {
            throw new BadRequestException("您不能在这里修改用户名或者是密码");
        }
        QueryWrapper<UsersRoles> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(UsersRoles::getUserId, user.getId());
        List<UsersRoles> usersRolesList = usersRolesMapper.selectList(queryWrapper);
        List<Long> oldRolesId = usersRolesList.stream().map(UsersRoles::getRoleId).collect(Collectors.toList());
        //求交集(不变的)
        List<Long> in = oldRolesId.stream().filter(rolesId::contains).collect(Collectors.toList());
        //删除的
        oldRolesId.removeAll(in);
        oldRolesId.forEach(oldRoleId -> {
            QueryWrapper<UsersRoles> usersRolesQueryWrapper = new QueryWrapper<>();
            usersRolesQueryWrapper.lambda()
                    .eq(UsersRoles::getUserId, user.getId())
                    .eq(UsersRoles::getRoleId, oldRoleId);
            usersRolesMapper.delete(usersRolesQueryWrapper);
        });
        //添加的
        rolesId.removeAll(in);
        rolesId.forEach(roleId -> {
            UsersRoles usersRoles = new UsersRoles();
            usersRoles.setRoleId(roleId);
            usersRoles.setUserId(user.getId());
            usersRolesMapper.insert(usersRoles);
        });
        if(jobsId == null){
            QueryWrapper<UsersJobs> deleteQueryWrapper = new QueryWrapper<>();
            deleteQueryWrapper.lambda().eq(UsersJobs::getUserId, user.getId());
            userJobsMapper.delete(deleteQueryWrapper);
        }else{
            QueryWrapper<UsersJobs> usersJobsQueryWrapper = new QueryWrapper<>();
            usersJobsQueryWrapper.lambda().eq(UsersJobs::getUserId, user.getId());
            List<UsersJobs> usersJobsList = userJobsMapper.selectList(usersJobsQueryWrapper);
            List<Long> oldJobsId = usersJobsList.stream().map(UsersJobs::getJobId).collect(Collectors.toList());
            //求交集(不变的)
            List<Long> jobIn = oldJobsId.stream().filter(jobsId::contains).collect(Collectors.toList());
            //删除的
            oldJobsId.removeAll(jobIn);
            oldJobsId.forEach(oldJobId -> {
                QueryWrapper<UsersJobs> deleteQueryWrapper = new QueryWrapper<>();
                deleteQueryWrapper.lambda()
                        .eq(UsersJobs::getUserId, user.getId())
                        .eq(UsersJobs::getJobId, oldJobId);
                userJobsMapper.delete(deleteQueryWrapper);
            });
            //添加的
            jobsId.removeAll(jobIn);
            jobsId.forEach(jobId -> {
                UsersJobs usersJobs = new UsersJobs();
                usersJobs.setUserId(user.getId());
                usersJobs.setJobId(jobId);
                userJobsMapper.insert(usersJobs);
            });
        }
        // 更新角色搜索
        StringBuilder roleIdStr = new StringBuilder(",");
        rolesId.forEach(roleId -> {
            roleIdStr.append(roleId).append(",");
        });
        user.setRoleIdStr(roleIdStr.toString());
        userMapper.updateById(user);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("更改成功");
        return resultMessage;
    }

    @Override
    @CacheEvict(allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    public ResultMessage delUser(Set<Long> ids) {
        userMapper.deleteBatchIds(ids);
        //删除用户对应的角色
        QueryWrapper<UsersRoles> queryWrapper = new QueryWrapper<>();
        ids.forEach(id -> {
            queryWrapper.lambda().or().eq(UsersRoles::getUserId, id);
        });
        usersRolesMapper.delete(queryWrapper);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("删除成功");
        return resultMessage;
    }

    @Override
    @Cacheable(key = "'username:' + #p0")
    public UserDto findByName(String userName) {
        UserDto userDto;
        QueryWrapper<UserDto> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(UserDto::getUsername, userName);
        userDto = userDtoMapper.selectOne(queryWrapper);
        if (userDto == null) {
            throw new EntityNotFoundException(User.class, "name", userName);
        }
        QueryWrapper<UsersRoles> usersRolesQueryWrapper = new QueryWrapper<>();
        usersRolesQueryWrapper.lambda().eq(UsersRoles::getUserId, userDto.getId());
        List<UsersRoles> usersRolesList = usersRolesMapper.selectList(usersRolesQueryWrapper);
        Set<RoleSmallDto> roleSmallDtoSet = new HashSet<>();
        //获得信息
        for (UsersRoles usersRoles : usersRolesList) {
            //获得相应的角色
            roleSmallDtoSet.add(roleSmallDtoMapper.selectById(usersRoles.getRoleId()));
        }
        userDto.setDept(deptSmallDtoMapper.selectById(userDto.getDeptId()));
        Set<JobSmallDto> jobSmallDtoSet = new HashSet<>();
        QueryWrapper<UsersJobs> usersJobsQueryWrapper = new QueryWrapper<>();
        usersJobsQueryWrapper.lambda().eq(UsersJobs::getUserId, userDto.getId());
        List<UsersJobs> usersJobsList = userJobsMapper.selectList(usersJobsQueryWrapper);
        usersJobsList.forEach(usersJobs -> {
            jobSmallDtoSet.add(jobSmallDtoMapper.selectById(usersJobs.getJobId()));
        });
        userDto.setRoles(roleSmallDtoSet);
        userDto.setJobs(jobSmallDtoSet);
        return userDto;
    }

    @Override
    @CacheEvict(allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    public ResultMessage editPass(String oldPass, String newPass) {
        UserDetails user = UserUtil.getCurrentUser();
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        ResultMessage resultMessage = new ResultMessage();
        assert user != null;
        if (!bCryptPasswordEncoder.matches(oldPass, user.getPassword())) {
            resultMessage.setStatus(HttpStatus.BAD_REQUEST.value());
            resultMessage.setMessage("当前密码不正确,请重新输入");
            return resultMessage;
        }
        if (bCryptPasswordEncoder.matches(newPass, user.getPassword())) {
            resultMessage.setStatus(HttpStatus.BAD_REQUEST.value());
            resultMessage.setMessage("处于安全考虑,您的密码不能和原来的密码相同");
            return resultMessage;
        }
        User oneUser = new User();
        oneUser.setId(UserUtil.getCurrentUserId());
        oneUser.setPassword(bCryptPasswordEncoder.encode(newPass));
        oneUser.setLastPasswordResetTime(new Timestamp(System.currentTimeMillis()));
        userMapper.updateById(oneUser);
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("更改密码成功,请重新登录");
        return resultMessage;
    }

    @Override
    @CacheEvict(allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    public ResultMessage editAvatar(MultipartFile avatar) {
        User user = userMapper.selectById(UserUtil.getCurrentUserId());
        String oldPath = user.getAvatar() == null ? "" : user.getAvatar();
        //上传文件并获得上传的文件路径
        FileUtil.FilePath filePath = FileUtil.uploadFile(avatar, "Avatar", FileUtil.FileType.PICTURE);
        UserDto userDto = new UserDto();
        userDto.setId(user.getId());
        userDto.setAvatar(filePath.getVisitPath());
        if (StringUtils.isNotBlank(oldPath)) {
            FileUtil.del(oldPath);
        }
        userDtoMapper.updateById(userDto);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("上传成功");
        return resultMessage;
    }

    @Override
    public ResultMessage getUserLevel() {
        QueryWrapper<UsersRoles> usersRolesQueryWrapper = new QueryWrapper<>();
        usersRolesQueryWrapper.lambda().eq(UsersRoles::getUserId, UserUtil.getCurrentUserId());
        List<UsersRoles> usersRolesList = usersRolesMapper.selectList(usersRolesQueryWrapper);
        Set<RoleSmallDto> roleSmallDtoSet = new HashSet<>();
        usersRolesList.forEach(usersRoles -> {
            roleSmallDtoSet.add(roleSmallDtoMapper.selectById(usersRoles.getRoleId()));
        });
        List<Integer> levelList = roleSmallDtoSet.stream().map(RoleSmallDto::getLevel).collect(Collectors.toList());
        Dict resultMap = Dict.create()
                .set("message", "请求成功")
                .set("level", Collections.min(levelList));
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setResultParam(resultMap);
        return resultMessage;
    }

    @Override
    public ResultMessage editMyUser(User user) {
        Long userId = UserUtil.getCurrentUserId();
        if (user.getId().equals(userId)) {
            throw new BadRequestException("您不能更改别人的用户");
        }
        User oneUser = new User();
        oneUser.setId(user.getId());
        oneUser.setNickName(user.getNickName());
        oneUser.setPhone(user.getPhone());
        oneUser.setSex(user.getSex());
        userMapper.updateById(oneUser);
        assert userId != null;
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("更改成功");
        return resultMessage;
    }

    /**
     * 检查用户权限 (将传进去的用户与当前用户进行比较)
     *
     * @param user 待检测的用户
     * @return
     */
    private void checkLevel(User user) {
        //获得当前用户的最高等级
        User currentUser = userMapper.selectById(UserUtil.getCurrentUserId());
        Integer currentMax = getMaxLevel(currentUser);
        if (currentMax.equals(1)) {
            return;
        }
        //获得用户的最高等级
        Integer max = getMaxLevel(user);
        ValidationUtil.isNull("添加的用户没有角色,请重新添加", max);
        //进行比较
        if (currentMax.compareTo(max) >= 0) {
            throw new BadRequestException("权限级别不足，您的权限级别" + currentMax + "低于等于权限级别" + max);
        }
    }

    /**
     * 获得用户的最高等级
     *
     * @param user
     * @return
     */
    private Integer getMaxLevel(User user) {
        QueryWrapper<UsersRoles> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(UsersRoles::getUserId, user.getId());
        List<UsersRoles> usersRolesList = usersRolesMapper.selectList(queryWrapper);
        Optional<Integer> currentMax = usersRolesList.stream()
                .map(usersRoles -> roleSmallDtoMapper.selectById(usersRoles.getRoleId()))
                .map(RoleSmallDto::getLevel).min(Comparator.naturalOrder());
        return currentMax.orElse(null);
    }
}
